package m.appserver;

import api.model.ApiAuthinfo;
import api.service.ApiAuthinfoService;
import com.alibaba.fastjson.JSONObject;
import io.netty.handler.codec.http.HttpHeaderNames;
import m.common.model.SessionModel;
import m.system.RuntimeData;
import m.system.cache.CacheUtil;
import m.system.exception.MException;
import m.system.util.GenerateID;
import m.system.util.ObjectUtil;
import m.system.util.StringUtil;
import m.system.util.SystemUtil;
import manage.dao.AdminLoginDao;
import manage.model.AdminAssist;
import manage.model.AdminLogin;
import manage.model.OrgGroupView;
import manage.service.AdminAssistService;
import manage.service.AdminGroupPowerService;
import manage.service.AdminLoginService;
import manage.service.ModuleService;

import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

public class AuthInfoUtil {
    private static final ThreadLocal<String> session = new ThreadLocal<>();
    private static final ThreadLocal<RequestUtil> request = new ThreadLocal<>();
    protected static void release(){
        session.remove();
        request.remove();
    }
    protected static void init(RequestUtil req){
        request.set(req);
        String sn=null;
        String authorization=req.getHeader("Authorization");
        if(!StringUtil.isSpace(authorization)) {
            String[] arr=authorization.split(" ");
            if(arr.length>1&&!StringUtil.isSpace(arr[1])&&!arr[1].equals("null")&&!arr[1].equals("undefined")) {
                sn=arr[1];
            }
        }
        String cookie=StringUtil.noSpace(req.getHeader(HttpHeaderNames.COOKIE));
        if(!cookie.isEmpty()){
            for(String cs : cookie.split(";")){
                if(cs.trim().contains(SESSION_NAME) &&cs.indexOf("=")>0) {
                    sn=cs.substring(cs.indexOf("=")+1);
                }
            }
        }
        if(null==sn){
            sn="no_cookie_"+ GenerateID.generatePrimaryKey();
            SystemUtil.println("no_cookie");
        }
        session.set(sn);
        //自动登录
        AdminLogin admin=AuthInfoUtil.getSessionModel(SESSION_LOGIN,AdminLogin.class);
        if(null==admin){
            String al=req.getCookieValue("admin_login");
            String name=req.getCookieValue("admin_name");
            String key=req.getCookieValue("admin_key");
            if(!StringUtil.isSpace(name)&&!StringUtil.isSpace(key)){
                if(StringUtil.isSpace(al)){//正常登录
                    try {
                        AdminLogin login=new AdminLogin();
                        login.setUsername(name);
                        login.setPassword(key);
                        admin= RuntimeData.getService(AdminLoginService.class).loginVerification(login);
                        setSessionAdmin(admin);
                        RuntimeData.getService(AdminLoginService.class).updateLastInfo(admin, req.getIpAddress());
                    } catch (Exception ignored) {}
                }else{//外协登录
                    try {
                        AdminAssist assist=new AdminAssist();
                        assist.setAdmin(new AdminLogin());
                        assist.getAdmin().setUsername(al);
                        assist.setUsername(name);
                        assist.setPassword(key);
                        assist=RuntimeData.getService(AdminAssistService.class).loginVerification(assist);
                        setSessionAssist(assist);
                        admin=assist.getAdmin();
                        RuntimeData.getService(AdminAssistService.class).updateLastInfo(assist,req.getIpAddress());
                    } catch (Exception ignored) {}
                }
            }
            if(null==admin){
                if(!StringUtil.isSpace(authorization)){
                    try {
                        admin=RuntimeData.getService(ApiAuthinfoService.class).auth(authorization, ApiAuthinfo.Type_Login,false);
                        setSessionAdmin(admin);
                    } catch (Exception ignored) {}
                    if(null==admin) {
                        String[] arr = authorization.split(" ");
                        if (arr.length >= 2) {
                            String adminOid = null;
                            try {
                                adminOid = RuntimeData.getDao(AdminLoginDao.class).getUserOid(arr[1]);
                            } catch (Exception ignored) {
                            }
                            if (!StringUtil.isSpace(adminOid)) {
                                try {
                                    admin = CacheUtil.get(AdminLogin.class, adminOid);
                                    setSessionAdmin(admin);
                                } catch (Exception ignored) {
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 线程调用 结束后请调用clear
     */
    public static void reset(RequestUtil request){
        if(null==session.get()){
            init(request);
        }
    }
    public static void clear(){release();}
    public static String getUri(){
        if(null!=request.get()){
            return request.get().getUri();
        }
        return null;
    }
    public static String getIpAddress(){
        if(null!=request.get()){
            return request.get().getIpAddress();
        }
        return null;
    }
    public static JSONObject getRequestJson() throws IOException {
        if(null!=request.get()){
            return request.get().getRequestJson();
        }
        return null;
    }
    public static String getSession(){
        String s=session.get();
        if(null==s) throw new RuntimeException("新线程使用AuthInfoUtil需先初始化，请调用AuthInfoUtil.reset方法设置。");
        return s;
    }
    public static String getSession(String flag){
        return getSession()+flag;
    }

    public final static String SESSION_NAME="session_name";

    private static final String SESSION_LOGIN="_admin_login";
    private static final String SESSION_ORG="_org_group";
    private static final String SESSION_ASSIST="_admin_assist";
    public final static MException noLoginException=new MException(AuthInfoUtil.class, "NoLogin:未登录");
    public final static MException noOrgException=new MException(AuthInfoUtil.class, "NoLogin:无机构权限");
    public final static MException noPowerException=new MException(AuthInfoUtil.class, "NoPower:权限不足");
    /** sessionLogin
     * 设置 session model
     */
    public static <T extends SessionModel> void setSessionModel(String sessionLogin, T model) {
        CacheUtil.push(AuthInfoUtil.getSession(sessionLogin), model.getOid());
    }
    /** sessionLogin
     * 获取 session model
     */
    public static <T extends SessionModel> T getSessionModel(String sessionLogin,Class<T> clazz) {
        String oid=(String) CacheUtil.get(AuthInfoUtil.getSession(sessionLogin));
        if(!StringUtil.isSpace(oid)) {
            return CacheUtil.get(clazz,oid);
        }
        return null;
    }
    /** sessionLogin
     * 清除 session model
     */
    public static void removeSessionModel(String sessionLogin) {
        CacheUtil.clear(AuthInfoUtil.getSession(sessionLogin));
    }


    /**
     * 获取登录用户信息 返回null说明没有登录
     *
     */
    public static AdminLogin getSessionAdmin() {
        return AuthInfoUtil.getSessionModel(SESSION_LOGIN,AdminLogin.class);
    }
    public static String getSessionAdminOid() throws MException {
        AdminLogin admin=getSessionAdmin();
        if(null==admin){
            throw noLoginException;
        }
        return admin.getOid();
    }

    /**
     * 设置当前登录部门oid
     */
    public static void setSessionOrgGroupId(String orgOid){
        CacheUtil.push(AuthInfoUtil.getSession(SESSION_ORG), orgOid);
    }

    /**
     * 获取当前登录部门
     */
    public static OrgGroupView getSessionOrgGroup() {
        String orgOid=(String)CacheUtil.get(AuthInfoUtil.getSession(SESSION_ORG));
        if(StringUtil.isSpace(orgOid)){
            AdminAssist assist=getSessionAssist();
            if(null!=assist&&!ObjectUtil.isEmptyOid(assist.getOrgGroup())){
                setSessionOrgGroupId(assist.getOrgGroup().getOid());
                return getSessionOrgGroup();
            }
            AdminLogin admin=getSessionAdmin();
            if(null!=admin&&!ObjectUtil.isEmptyOid(admin.getOrgGroup())){
                setSessionOrgGroupId(admin.getOrgGroup().getOid());
                return getSessionOrgGroup();
            }
            return null;
        }
        return CacheUtil.get(OrgGroupView.class,orgOid);
    }
    public static String getSessionOrgGroupOid() throws MException {
        OrgGroupView org=getSessionOrgGroup();
        if(null==org){
            throw noOrgException;
        }
        return org.getOid();
    }

    /**
     * 设置外协session 并设置管理员和登录部门
     */
    public static void setSessionAssist(AdminAssist assist){
        AuthInfoUtil.setSessionModel(SESSION_ASSIST,assist);
        setSessionAdmin(assist.getAdmin());
        if(!ObjectUtil.isEmptyOid(assist.getOrgGroup())){
            setSessionOrgGroupId(assist.getOrgGroup().getOid());
        }else{
            setSessionOrgGroupId("");
        }
    }

    /**
     * 获取当前登录的外协账号
     */
    public static AdminAssist getSessionAssist(){
        return AuthInfoUtil.getSessionModel(SESSION_ASSIST,AdminAssist.class);
    }
    /**
     * 设置session
     *  admin 登录人信息
     */
    public static void setSessionAdmin(AdminLogin admin){
        if(null==admin) return;
        AuthInfoUtil.setSessionModel(SESSION_LOGIN,admin);
        if(!ObjectUtil.isEmptyOid(admin.getOrgGroup())){
            setSessionOrgGroupId(admin.getOrgGroup().getOid());
        }else{
            setSessionOrgGroupId("");
        }
    }
    /**
     * 清除登录信息
     */
    public static void clearSessionAdmin(){
        AuthInfoUtil.removeSessionModel(SESSION_LOGIN);
        AuthInfoUtil.removeSessionModel(SESSION_ASSIST);
        CacheUtil.clear(AuthInfoUtil.getSession(SESSION_ORG));
    }
    public static Map<String,Boolean> getAdminOperPower() throws SQLException, MException {
        AdminLogin admin=getSessionAdmin();
        if(null!=admin){
            OrgGroupView org=getSessionOrgGroup();
            return RuntimeData.getService(AdminGroupPowerService.class).getPowerMap(admin.getOid(),null!=org?org.getOid():"");
        }else{
            return new HashMap<>();
        }
    }
    /**
     * 验证操作权限
     *  power 在module.xml配置文件中配置  如果传入多个, 有一个满足即可
     */
    public static AdminLogin verifyAdminOperPower(String... power) throws Exception{
        AdminLogin login=verifyAdminLogin();
        if(power.length==0||power.length==1&&StringUtil.isSpace(power[0])) throw noPowerException;
        OrgGroupView org=getSessionOrgGroup();
        if(RuntimeData.getService(AdminGroupPowerService.class).hasPower(login.getOid(),null!=org?org.getOid():"", power)){
            return login;
        }else{
            throw noPowerException;
        }
    }
    /**
     * 判断是否有操作权限  如果传入多个, 有一个满足即可
     */
    public static boolean hasAdminOperPower(String... power) throws Exception {
        AdminLogin login=verifyAdminLogin();
        if(power.length==0||power.length==1&&StringUtil.isSpace(power[0])) return false;
        OrgGroupView org=getSessionOrgGroup();
        return RuntimeData.getService(AdminGroupPowerService.class).hasPower(login.getOid(),null!=org?org.getOid():"", power);
    }
    /**
     * 判断当前登录人是否有菜单操作权限，有一个满足即可
     */
    public static void verifyMenu(String... menuOid) throws Exception {
        AdminLogin login = verifyAdminLogin();
        OrgGroupView org=getSessionOrgGroup();
        boolean flag=false;
        for(String oid : menuOid) {
            if(null!=RuntimeData.getService(ModuleService.class).getMenuUrl(oid,login.getOid(),null!=org?org.getOid():"")){
                flag=true;
                break;
            }
        }
        if(!flag) throw new MException(AuthInfoUtil.class,"无此菜单权限");
    }

    /**
     * 验证登录 未登录则报错
     */
    public static AdminLogin verifyAdminLogin() throws Exception{
        AdminLogin model=getSessionAdmin();
        if(null!=model){
            return model;
        }else{
            throw noLoginException;
        }
    }
}
